module.exports = {


  friendlyName: 'Download one vulnerability CSV',


  description: 'Download a CSV containing information about a single vulnerability',


  inputs: {

    cveId: {
      decription: 'The CVE ID of the vulnerability that an CSV export will be created for.',
      type: 'string',
      required: true
    },

    teamApid: {
      description: 'The ID of the Team to filter by, or 0 to only include hosts with no team, or undefined to not filter by any team.',
      type: 'number',
    },

  },


  exits: {
    success: {
      outputFriendlyName: 'File',
      outputDescription: 'The streaming bytes of the file.',
      outputType: 'ref'
    },
  },


  fn: async function ({cveId, teamApid}) {

    // Generate a random room name.
    let roomId = await sails.helpers.strings.random();
    if(this.req.isSocket) {
      // Add the requesting socket to the room.
      sails.sockets.join(this.req, roomId);
    }

    let report = await sails.helpers.getVulnerabilities.with({cveId: cveId, teamApid: teamApid});

    if(report.entries.length === 0) {
      throw new Error(`Unexpected error: When generating a CSV export for a single vulnerability (with the CVE id ${cveId}), the vulnerability was not found in the database.`);
    }
    let thisVulnerability = report.entries[0];

    let stream = require('stream');
    let csvString = '';
    // Create a writeable stream we'll use to create the csvString.
    let writableStream = new stream.Writable({//[?]: https://nodejs.org/api/stream.html#writable_writechunk-encoding-callback
      write(chunk, encoding, callback) {
        csvString += chunk.toString();
        callback();
      }
    });

    let csv = require('fast-csv');
    let generatingCsv = csv.format({ headers: true });
    // Pass the writableStream into generatingCsv.
    generatingCsv.pipe(writableStream);// [?]: https://c2fo.github.io/fast-csv/docs/formatting/methods#write

    // Build the CSV report
    for(let host of thisVulnerability.affectedHosts){
      let installsForThisHost = thisVulnerability.affectedInstalls.filter((install) => {
        return install.affectedHost === host.id;
      });
      // Add a row for each vulnerable install.
      for(let install of installsForThisHost) {
        let csvRow = {};
        csvRow['CVE ID'] = thisVulnerability.cveId;
        csvRow['Severity'] = thisVulnerability.severity;
        csvRow['Has known exploit'] = !! thisVulnerability.hasKnownExploit;
        csvRow['CVE description'] = thisVulnerability.cveDescription ? thisVulnerability.cveDescription : 'N/A';
        csvRow['Publish date'] = new Date(thisVulnerability.publishedAt);
        csvRow['Affected software name'] = install.name;
        csvRow['Affected software version'] = install.version;
        csvRow['Resolved in version'] = install.resolvedInVersion ? install.resolvedInVersion : 'N/A';
        csvRow['Affected software URL'] = install.url;
        csvRow['Vulnerable software detected on'] = new Date(install.installedAt);
        csvRow['Host Fleet URL'] = sails.config.custom.fleetBaseUrl + '/hosts/' + encodeURIComponent(host.fleetApid);
        csvRow['Host display name'] = host.displayName;
        csvRow['Host team'] = host.teamDisplayName;
        csvRow['Host serial number'] = host.hardwareSerialNumber;
        csvRow['Host UUID'] = host.uuid;
        csvRow['Host team ID'] = host.teamApid !== 0 ? host.teamApid : 'N/A';
        // Add this row to the generatingCsv
        generatingCsv.write(csvRow);
      }//∞
    }
    generatingCsv.end();

    // After the the csvString has been generated by the writableStream, broadcast the csvString to the requesting user's socket.
    writableStream.on('finish', () => {
      if(this.req.isSocket){
        // Note: we're sending the cveId with the cvsString, this is so we can set the filename in our frontend code.
        sails.sockets.broadcast(roomId, 'singleCsvExportDone', {csv: csvString, cveId});
        // Unsubscribe the socket from the room.
        sails.sockets.leave(this.req, roomId);
      } else {
        return csvString;
      }
    });
  }


};
